﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Security.Principal;
using System.Web.SessionState;
using System.Web.Security;
using System.Text;

namespace HaiFang
{
    public class CustomPrincipal : IPrincipal
    {
        private IIdentity mIdentity;

        public CustomPrincipal(IIdentity identity)
        {
            mIdentity = identity;
        }

        public IIdentity Identity
        {
            get { return mIdentity; }
        }

        public bool IsInRole(string role)
        {
            return false;
        }

    }

    public class CustomAuthorizeModule : IHttpModule
    {
        public void Dispose()
        {
        }

        public void Init(HttpApplication context)
        {
            context.PostAuthenticateRequest += new EventHandler(context_PostAuthenticateRequest);
        }

        void context_PostAuthenticateRequest(object sender, EventArgs e)
        {
            HttpApplication context = sender as HttpApplication;
            if (context.User.Identity is FormsIdentity)
            {
                context.Context.User = new CustomPrincipal(new CustomIdentity(context.User.Identity.Name, ((FormsIdentity)context.User.Identity).Ticket));
            }
            else
            {
                context.Context.User = new CustomPrincipal(context.User.Identity);
            }
        }
    }

    public class CustomIdentity : GenericIdentity
    {
        public FormsAuthenticationTicket Ticket { get; private set; }

        public CustomIdentity(string name, FormsAuthenticationTicket ticket)
            : base(name)
        {
            if (ticket != null)
            {
                this.UserInfo = SimpleUserInfo.ExtrackFromUserData(ticket.UserData);
            }
        }

        public SimpleUserInfo UserInfo { get; private set; }
    }

    public class SimpleUserInfo : UserInfoWithProject
    {
        protected Dictionary<string, string> GetUserData()
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();
            dic.Add("AutoID", this.AutoID.ToString());
            dic.Add("CreateTime", this.CreateTime.ToString());
            dic.Add("Description", this.Description);
            dic.Add("GroupID", this.GroupID.ToString());
            dic.Add("GUID", this.GUID);
            dic.Add("LastCheckTime", this.LastCheckTime.ToString());
            dic.Add("LastLoginTime", this.LastLoginTime.ToString());
            dic.Add("LockCount", this.LockCount.ToString());
            dic.Add("LockTime", this.LockTime.ToString());
            dic.Add("Password", this.Password);
            dic.Add("ProjectID", this.ProjectID.ToString());
            dic.Add("UserName", this.UserName);
            return dic;
        }

        protected virtual void SetUserData(Dictionary<string, string> dictionary)
        {
            if (dictionary.ContainsKey("AutoID"))
            {
                this.AutoID = Convert.ToInt32(dictionary["AutoID"]);
            }
            if (dictionary.ContainsKey("CreateTime"))
            {
                this.CreateTime = Convert.ToDateTime(dictionary["CreateTime"]);
            }
            if (dictionary.ContainsKey("Description"))
            {
                this.Description = (dictionary["Description"]);
            }
            if (dictionary.ContainsKey("GroupID"))
            {
                this.GroupID = Convert.ToInt32(dictionary["GroupID"]);
            }
            if (dictionary.ContainsKey("GUID"))
            {
                this.GUID = dictionary["GUID"];
            }
            if (dictionary.ContainsKey("LastCheckTime"))
            {
                this.LastCheckTime = Convert.ToDateTime(dictionary["LastCheckTime"]);
            }
            if (dictionary.ContainsKey("LastLoginTime"))
            {
                this.LastLoginTime = Convert.ToDateTime(dictionary["LastLoginTime"]);
            }
            if (dictionary.ContainsKey("LockCount"))
            {
                this.LockCount = Convert.ToInt32(dictionary["LockCount"]);
            }
            if (dictionary.ContainsKey("LockTime"))
            {
                this.LockTime = Convert.ToDateTime(dictionary["LockTime"]);
            }
            if (dictionary.ContainsKey("Password"))
            {
                this.Password = (dictionary["Password"]);
            }
            if (dictionary.ContainsKey("ProjectID"))
            {
                this.ProjectID = Convert.ToInt32(dictionary["ProjectID"]);
            }
            if (dictionary.ContainsKey("UserName"))
            {
                this.UserName = (dictionary["UserName"]);
            }
        }

        public static SimpleUserInfo ExtrackFromUserData(string userdata)
        {
            if (string.IsNullOrEmpty(userdata))
            {
                return null;
            }
            else
            {
                string[] pairs = userdata.Split(new char[] { '&' });
                Dictionary<string, string> dictionary = new Dictionary<string, string>();
                foreach (var str in pairs)
                {
                    string[] pair = str.Split(new char[] { '=' });
                    if (pair.Length == 2)
                    {
                        dictionary.Add(pair[0], pair[1]);
                    }
                    else if(pair.Length>2)
                    {
                        //密码之中包含=号
                        dictionary.Add(pair[0],str.Substring(pair[0].Length+1));                        
                    }
                }
                SimpleUserInfo userinfo = new SimpleUserInfo();
                userinfo.SetUserData(dictionary);
                return userinfo;
            }
        }

        public static string GetUserInfoData(SimpleUserInfo user)
        {
            if (user == null)
            {
                return null;
            }
            var dic = user.GetUserData();
            List<string> arr = new List<string>();
            foreach (var k in dic.Keys)
            {
                arr.Add(string.Format("{0}={1}", k, dic[k]));
            }
            return string.Join("&", arr.ToArray());
        }

        public static SimpleUserInfo GetSimpleUserInfo(UserInfoWithProject ui)
        {
            SimpleUserInfo sui = new SimpleUserInfo();
            sui.AutoID = ui.AutoID;
            sui.CreateTime = ui.CreateTime;
            sui.Description = ui.Description;
            sui.GroupID = ui.GroupID;
            sui.GUID = ui.GUID;
            sui.LastCheckTime = ui.LastCheckTime;
            sui.LastLoginTime = ui.LastLoginTime;
            sui.LockCount = ui.LockCount;
            sui.LockTime = ui.LockTime;
            sui.Password = ui.Password;
            sui.ProjectID = ui.ProjectID;
            sui.UserName = ui.UserName;
            return sui;
        }
    }

    public sealed class CustomAuthentication
    {
        private static int _timeout = 60;

        public static int TIMEOUT
        {
            get { return _timeout; }
            set { _timeout = value; }
        }

        public static string DefaultUrl
        {
            get { return FormsAuthentication.DefaultUrl; }
        }

        public static string LoginUrl
        {
            get { return FormsAuthentication.LoginUrl; }
        }

        public static int Authenticate(string username, string password)
        {
            int r = -1;
            UserInfoWithProject ui = ProxyUserInfo.CheckLogin(username, password, ClientIP, string.Empty, out r);
            if (r == 0)
            {
                if (ui != null)
                {
                    SetAuthCookie(ui.UserName, SimpleUserInfo.GetSimpleUserInfo(ui));
                }
            }
            return r;
        }

        public static void SetAuthCookie(string userName, SimpleUserInfo userInfo)
        {
            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
                           userName,
                           DateTime.Now,
                           DateTime.Now.AddMinutes(_timeout),
                           false,
                           SimpleUserInfo.GetUserInfoData(userInfo),
                           FormsAuthentication.FormsCookiePath);

            // Encrypt the ticket.
            string encTicket = FormsAuthentication.Encrypt(ticket);
            // Create the cookie.
            HttpContext.Current.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket) { Path = FormsAuthentication.FormsCookiePath });
        }

        public static void SignOut()
        {
            if (HttpContext.Current.User.Identity is CustomIdentity)
            {
                FormsAuthentication.RenewTicketIfOld(((CustomIdentity)HttpContext.Current.User.Identity).Ticket);
            }
            FormsAuthentication.SignOut();
        }

        public static void RedirectToLoginPage()
        {
            HttpContext.Current.Response.Redirect(LoginUrl + "?ReturnUrl=" + HttpUtility.UrlEncode(HttpContext.Current.Request.Url.ToString()));
        }

        public static void RedirectToDefaultPage()
        {
            HttpContext.Current.Response.Redirect(DefaultUrl);
        }

        public static string ClientIP
        {
            get
            {
                string result = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
                if (null == result || result == String.Empty)
                {
                    result = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
                }

                if (null == result || result == String.Empty)
                {
                    result = HttpContext.Current.Request.UserHostAddress;
                }
                return result;
            }
        }
    }
}
